package com.lwl.mini.executor;

import com.lwl.mini.cache.LocalCache;
import com.lwl.mini.executor.statement.StatementHandler;
import com.lwl.mini.mapping.MapperStatement;
import com.lwl.mini.session.Configuration;
import com.lwl.mini.transaction.Transaction;
import com.lwl.mini.util.ObjectUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * 执行器
 * @author lwl
 * @create 2022/4/15 9:56
 */
public class DefaultExecutor implements Executor {

    private final Configuration configuration;
    private final Transaction transaction;
    private final LocalCache cache;

    public DefaultExecutor(Configuration configuration, Transaction transaction) {
        this.configuration = configuration;
        this.transaction = transaction;
        cache = LocalCache.getInstance();
    }


    @Override
    public <E> List<E> query(MapperStatement statement) {
        boolean cacheEnable = configuration.getSettings().get("cacheEnable");
        LocalCache instance = LocalCache.getInstance();
        String key = generateKey(statement);
        if (cacheEnable) {
            //开启了本地缓存
            Object obj = instance.get(key);
            if (obj != null) {
                //若本地缓存中有相应结果，则不需要执行jdbc查询操作了
                return (List<E>) obj;
            }
        }
        //未开启本地缓存或是本地缓存中无该缓存信息
        List<E> objects = doQuery(statement);
        if(cacheEnable){
            //开启了本地缓存，即放入缓存中
            instance.put(key,objects);
        }
        return objects;
    }

    @Override
    public <E> List<E> doQuery(MapperStatement statement) {
        PreparedStatement stmt = null;
        ResultSet result = null;
        try {
            StatementHandler statementHandler = configuration.newStatementHandler(statement);
            stmt = prepareStatement(statementHandler);
            result = execute(statementHandler, stmt);
            return result == null?null:(List<E>)handlerResult(statementHandler, result);
        }finally {
            if(result!=null){
                try {
                    result.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(stmt!=null){
                try {
                    stmt.close();
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    @Override
    public List<Integer> doUpdate(MapperStatement statement) {
        PreparedStatement stmt = null;
        List<Integer> res = new ArrayList<>();
        try {
            StatementHandler statementHandler = configuration.newStatementHandler(statement);
            stmt = prepareStatement(statementHandler);
            boolean loggedEnable = configuration.getSettings().get("loggedEnable");
            if(loggedEnable){
                System.out.println(ObjectUtils.currentTime() + " 执行语句为: " + stmt);
            }
            int i = stmt.executeUpdate();
            res.add(i);
            return res;
        } catch (SQLException e) {
            throw new ExecutorException("执行阶段出现异常:"+e,e);
        } finally {
            if(stmt!=null){
                try {
                    stmt.close();
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    @Override
    public void close() {
        if(transaction!=null){
            try {
                transaction.close();
            } catch (SQLException sqlException) {
                sqlException.printStackTrace();
            }
        }
    }

    @Override
    public void commit() {
        try {
            transaction.commit();
        } catch (SQLException sqlException) {
            sqlException.printStackTrace();
        }
    }

    /**
     * 调用PreparedStatement执行SQL语句预处理
     */
    private PreparedStatement prepareStatement(StatementHandler statementHandler) {
        Connection connection = transaction.getConnection();
        PreparedStatement statement = statementHandler.prepare(connection);
        return statement;
    }

    /**
     * 调用DefaultResultSetHandler处理结果集
     */
    private ResultSet execute(StatementHandler statementHandler, PreparedStatement stmt) {
        ResultSet res = statementHandler.executeQuery(stmt);
        return res;
    }

    private Object handlerResult(StatementHandler statementHandler,ResultSet resultSet){
        return statementHandler.handlerResult(resultSet);
    }

    public String generateKey(MapperStatement statement) {
        return statement.generateKey();
    }
}
